#include "detr.h"
#include "global.h"
std::vector<NonRecognitionAreaAttr> NoRecognitionAreaAttrs;

class LetterBox
{
   private:
    cv::Size new_shape;
    bool auto_flag;
    bool scaleFill;
    bool scaleup;
    int stride;

   public:
    // 构造函数
    LetterBox(cv::Size new_shape = cv::Size(640, 640), bool auto_flag = false,
              bool scaleFill = false, bool scaleup = true, int stride = 32)
        : new_shape(new_shape),
          auto_flag(auto_flag),
          scaleFill(scaleFill),
          scaleup(scaleup),
          stride(stride)
    {
    }

    // 调用运算符重载
    cv::Mat operator()(const cv::Mat &img, double &ratio, double &pad_w, double &pad_h)
    {
        cv::Size shape = img.size();

        // 计算缩放比例
        double r = std::min(static_cast<double>(new_shape.height) / shape.height,
                            static_cast<double>(new_shape.width) / shape.width);
        if (!scaleup)
        {
            r = std::min(r, 1.0);
        }
        ratio = r;
        // 计算新的未填充尺寸
        cv::Size new_unpad = cv::Size(static_cast<int>(std::round(shape.width * r)),
                                      static_cast<int>(std::round(shape.height * r)));

        // 计算填充量
        double dw = new_shape.width - new_unpad.width;
        double dh = new_shape.height - new_unpad.height;

        if (auto_flag)
        {
            dw = std::fmod(dw, stride);
            dh = std::fmod(dh, stride);
        }
        else if (scaleFill)
        {
            dw = 0.0;
            dh = 0.0;
            new_unpad = new_shape;
            r = static_cast<double>(new_shape.width) / shape.width;
        }

        dw /= 2;
        dh /= 2;

        pad_w = dw;
        pad_h = dh;

        cv::Mat resized_img;
        if (shape != new_unpad)
        {
            cv::resize(img, resized_img, new_unpad, 0, 0, cv::INTER_LINEAR);
        }
        else
        {
            resized_img = img.clone();
        }

        // 计算填充的边界
        int top = static_cast<int>(std::round(dh - 0.1));
        int bottom = static_cast<int>(std::round(dh + 0.1));
        int left = static_cast<int>(std::round(dw - 0.1));
        int right = static_cast<int>(std::round(dw + 0.1));

        // 添加填充
        cv::Mat padded_img;
        cv::copyMakeBorder(resized_img, padded_img, top, bottom, left, right, cv::BORDER_CONSTANT,
                           cv::Scalar(114, 114, 114));

        return padded_img;
    }
};

static float Calcinter(const std::vector<float> &box1, const std::vector<float> &box2)
{
    float area1 = box1[6];
    float area2 = box2[6];
    float xx1 = std::max(box1[0], box2[0]);
    float yy1 = std::max(box1[1], box2[1]);
    float xx2 = std::min(box1[2], box2[2]);
    float yy2 = std::min(box1[3], box2[3]);
    float w = std::max(0.0f, xx2 - xx1 + 1);
    float h = std::max(0.0f, yy2 - yy1 + 1);
    float inter = w * h;
    float ovr = inter / (area1 + area2 - inter);
    return ovr;
}

enum VaildBoxId
{
    SCORE_IDX = 0,
    XCENTER_IDX = 1,
    YCENTER_IDX = 2,
    W_IDX = 3,
    H_IDX = 4,
    CLSAA_ID_IDX = 5
};

enum BoxValue
{
    TOP_LEFT_X = 0,
    TOP_LEFT_Y = 1,
    BOTTOM_RIGHT_X = 2,
    BOTTOM_RIGHT_Y = 3,
    SCORE = 4,
    CLASS_ID = 5,
    BBOX_SIZE = 6
};

enum InputOutputId
{
    INPUT_IMG_ID = 0,
    OUTPUT_NUM_ID = 0,
    OUTPUT_BBOX_ID = 1
};

static void MulticlassNms(std::vector<std::vector<float>> &bboxes,
                          const std::vector<std::vector<float>> &vaildBox, float nmsThr)
{
    for (auto &item : vaildBox)
    { /* score, xcenter, ycenter, w, h, classId */
        float boxXCenter = item[XCENTER_IDX];
        float boxYCenter = item[YCENTER_IDX];
        float boxWidth = item[W_IDX];
        ;
        float boxHeight = item[H_IDX];
        ;

        float x1 = (boxXCenter - boxWidth / 2);
        float y1 = (boxYCenter - boxHeight / 2);
        float x2 = (boxXCenter + boxWidth / 2);
        float y2 = (boxYCenter + boxHeight / 2);
        float area = (x2 - x1 + 1) * (y2 - y1 + 1);
        bool keep = true;
        /* lx, ly, rx, ry, score, class id, area */
        std::vector<float> bbox {x1, y1, x2, y2, item[SCORE_IDX], item[CLSAA_ID_IDX], area};
        for (size_t j = 0; j < bboxes.size(); j++) {
            if (Calcinter(bbox, bboxes[j]) > nmsThr) {
                keep = false;
                break;
            }
        }
        if (keep)
        {
            bboxes.push_back(bbox);
        }
    }
}

inline static float Sigmod(float a) { return 1.0f / (1.0f + exp(-a)); }

static void GetMaxScoreAndIdx(uint32_t objScoreIdx, uint32_t chnStep, const float *outData,
                              float &maxclsSCore, uint32_t &maxClsInx)
{
    uint32_t clsScoreIdx = objScoreIdx + chnStep;
    for (uint32_t c = 0; c < CLASS_NUM; c++)
    {
        float clsScoreVal = outData[clsScoreIdx];
        if (clsScoreVal > maxclsSCore)
        {
            maxclsSCore = clsScoreVal;
            maxClsInx = c;
        }
        clsScoreIdx += chnStep;
    }
}

static void ProcessPerDectectionInner(const DetectionInnerParam &innerParam,
                                      const std::vector<float> &gridsX,
                                      const std::vector<float> &gridsY,
                                      const std::vector<std::vector<uint32_t>> &anchorGrids,
                                      std::vector<std::vector<float>> &vaildBox)
{
    std::vector<uint32_t> expandedStrides{32, 16, 8}; /* 8: 16 : 32: anchor size */
    uint32_t outHeightIdx = innerParam.outHeightIdx;
    uint32_t chnStep = innerParam.chnStep;
    float scoreThr = innerParam.scoreThr;
    float *outData = innerParam.outData;
    size_t wStrideOffset = innerParam.wStrideOffset;
    uint32_t objScoreOffset = innerParam.objScoreOffset;
    uint32_t offset = outHeightIdx * innerParam.wStrideOffset;
    for (uint32_t j = 0; j < innerParam.outWidth; j++)
    {
        for (uint32_t k = 0; k < SCALE_SIZE; k++)
        {
            offset = j + outHeightIdx * wStrideOffset + k * chnStep * OUT_PARM_NUM;
            uint32_t objScoreIdx = offset + objScoreOffset;
            float objScoreVal = Sigmod(outData[objScoreIdx]);
            if (objScoreVal <= scoreThr)
            {
                continue;
            }
            /* max score */
            float maxclsSCore = 0.0f;
            uint32_t maxClsInx = 0;
            GetMaxScoreAndIdx(objScoreIdx, chnStep, outData, maxclsSCore, maxClsInx);

            float confidenceScore = Sigmod(maxclsSCore) * objScoreVal;
            if (confidenceScore > scoreThr)
            {
                /* gen box  info */
                uint32_t xCenterIdx = offset;
                uint32_t yCenterIdx = xCenterIdx + chnStep;
                uint32_t boxWidthIdx = yCenterIdx + chnStep;
                uint32_t boxHieghtIdx = boxWidthIdx + chnStep;
                float xCenter = (Sigmod(outData[xCenterIdx]) * 2 + gridsX[j]) *  // 2: alg param
                                expandedStrides[innerParam.detectIdx];           // 2: alg param
                float yCenter =
                    (Sigmod(outData[yCenterIdx]) * 2 + gridsY[outHeightIdx]) *  // 2: alg param
                    expandedStrides[innerParam.detectIdx];
                float tmpValue = Sigmod(outData[boxWidthIdx]) * 2;  // 2: alg param
                float boxWidth = tmpValue * tmpValue * anchorGrids[innerParam.detectIdx][(k << 1)];
                tmpValue = Sigmod(outData[boxHieghtIdx]) * 2;  // 2: alg param
                float boxHieght =
                    tmpValue * tmpValue * anchorGrids[innerParam.detectIdx][(k << 1) + 1];

                vaildBox.push_back({confidenceScore, xCenter, yCenter, boxWidth, boxHieght,
                                    static_cast<float>(maxClsInx)});
            }
        }
    }
}

static void PrintResult(const std::vector<std::vector<float>> &boxValue)
{
    if (boxValue.empty())
    {
        custom_printf("input box empty");
        return;
    }
    std::vector<int> clsNum;
    float cId = boxValue[0][CLASS_ID];
    int validNum = 0;
    for (size_t loop = 0; loop < boxValue.size(); loop++)
    {
        if (boxValue[loop][CLASS_ID] == cId)
        {
            validNum++;
        }
        else
        {
            clsNum.push_back(validNum);
            cId = boxValue[loop][CLASS_ID];
            validNum = 1;
        }
    }
    clsNum.push_back(validNum);
    int idx = 0;
    int sumNum = 0;
    custom_printf("current class valid box number is: %d", clsNum[idx]);
    sumNum += clsNum[idx];
    size_t totalBoxNum = boxValue.size();
    for (size_t loop = 0; loop < totalBoxNum; loop++)
    {
        if (loop == static_cast<size_t>(sumNum))
        {
            idx++;
            custom_printf("current class valid box number is: %d", clsNum[idx]);
            sumNum += clsNum[idx];
        }
        custom_printf("lx: %.0f, ly: %.0f, rx: %.0f, ry: %.0f, score: %.0f; class id: %d",
                      boxValue[loop][TOP_LEFT_X], boxValue[loop][TOP_LEFT_Y],
                      boxValue[loop][BOTTOM_RIGHT_X], boxValue[loop][BOTTOM_RIGHT_Y],
                      boxValue[loop][SCORE], (int)boxValue[loop][CLASS_ID]);
    }
}

bool Detection::Init(std::string mode_path, std::string acl_file_path)
{
    if (!InitResource(acl_file_path))
    {
        custom_printf("InitResource failed\n");
        return false;
    }

    if (!LoadModel(mode_path))
    {
        custom_printf("LoadModel failed\n");
        return false;
    }

    if (!CreateOutput())
    {
        custom_printf("create output failed");
    }
    if (!CreateInput())
    {
        custom_printf("create input failed");
    }

    // add rpn paras
    if (!SetDetParas())
    {
        custom_printf("set det paras failed");
    }

    if (!CreateTaskBufAndWorkBuf())
    {
        custom_printf("create taskbuf and workbuf failed");
    }

    // custom_printf("Detection init success");
    return true;
}

bool Detection::InitResource(std::string acl_file_path)
{
    // ACL init
    if (svp_acl_init(acl_file_path.c_str()) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl init failed\n");
        return false;
    }

    // set device
    if (svp_acl_rt_set_device(deviceId_) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl open device %d false.\n", deviceId_);
        return false;
    }

    // set no timeout
    if (svp_acl_rt_set_op_wait_timeout(0) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl set op wait time false.\n");
        return false;
    }

    // create context (set current)
    if (svp_acl_rt_create_context(&context_, deviceId_) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl create context false.\n");
        return false;
    }

    // create stream
    if (svp_acl_rt_create_stream(&stream_) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl create stream false.\n");
        return false;
    }

    // get run mode
    svp_acl_rt_run_mode runMode;
    if (svp_acl_rt_get_run_mode(&runMode) != SVP_ACL_SUCCESS)
    {
        custom_printf("acl get run mode false.\n");
        return false;
    }
    if (runMode != SVP_ACL_DEVICE)
    {
        custom_printf("acl run mode false.\n");
        return false;
    }
    return true;
}

bool Detection::LoadModel(std::string mode_path)
{
    if (!LoadModelFromFileWithMem(mode_path.c_str()))
    {
        custom_printf("execute LoadModelFromFileWithMem failed");
        return false;
    }

    // create model description
    modelDesc_ = svp_acl_mdl_create_desc();
    if (modelDesc_ == nullptr)
    {
        custom_printf("create model description failed");
        return false;
    }

    svp_acl_error ret = svp_acl_mdl_get_desc(modelDesc_, modelId_);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("get model description failed");
        return false;
    }

    // custom_printf("create model description success");
    return true;
}

void Detection::DumpModelDesc()
{
    custom_printf("model id is %d", modelId_);
    // custom_printf("model input num is %d",
    // svp_acl_mdl_get_num_inputs(modelDesc_));
    custom_printf("model output num is %d", svp_acl_mdl_get_num_outputs(modelDesc_));

    for (size_t i = 0; i < svp_acl_mdl_get_num_inputs(modelDesc_); ++i)
    {
        custom_printf("model input size is %d", svp_acl_mdl_get_input_size_by_index(modelDesc_, 0));
        svp_acl_mdl_io_dims dims;
        svp_acl_mdl_get_input_dims(modelDesc_, 0, &dims);
        custom_printf("model intput %d tensor name is %s,dim array count is %d", i, dims.name,
                      dims.dim_count);
        for (size_t j = 0; j < dims.dim_count; ++j)
        {
            custom_printf("model intput %d tensor dim %d is %d", i, j, dims.dims[j]);
        }
    }

    for (size_t i = 0; i < svp_acl_mdl_get_num_outputs(modelDesc_); ++i)
    {
        custom_printf("model output size is %d",
                      svp_acl_mdl_get_output_size_by_index(modelDesc_, i));
        svp_acl_mdl_io_dims dims;
        svp_acl_mdl_get_output_dims(modelDesc_, 0, &dims);
        custom_printf("model output %d tensor name is %s,dim array count is %d", i, dims.name,
                      dims.dim_count);
        for (size_t j = 0; j < dims.dim_count; ++j)
        {
            custom_printf("model output %d tensor dim %d is %d", i, j, dims.dims[j]);
        }
    }

    custom_printf("model input name index is %s",
                  svp_acl_mdl_get_input_name_by_index(modelDesc_, 0));
    custom_printf("model output name index is %s",
                  svp_acl_mdl_get_output_name_by_index(modelDesc_, 0));

    custom_printf("model input format is %d", svp_acl_mdl_get_input_format(modelDesc_, 0));
    custom_printf("model output format is %d", svp_acl_mdl_get_output_format(modelDesc_, 0));
    custom_printf("model input datatype is %d", svp_acl_mdl_get_input_data_type(modelDesc_, 0));
    custom_printf("model output datatype is %d", svp_acl_mdl_get_output_data_type(modelDesc_, 0));

    // svp_acl_mdl_get_input_index_by_name(modelDesc_, 0,&index);
    // custom_printf("model input indexname is %ld", index);
    // svp_acl_mdl_get_output_index_by_name(modelDesc_, 0,&index);
    // custom_printf("model output indexname is %ld", index);

    custom_printf("model input defaultstride is %d",
                  svp_acl_mdl_get_input_default_stride(modelDesc_, 0));
    custom_printf("model output defaultstride is %d",
                  svp_acl_mdl_get_output_default_stride(modelDesc_, 0));

    svp_acl_mdl_hw hw;
    svp_acl_mdl_get_dynamic_hw(modelDesc_, 0, &hw);
    custom_printf("model height&width array count is %d,hight is %d,width is %d", hw.hw_count,
                  hw.hw[0][0], hw.hw[0][1]);

    size_t calss_id;
    svp_acl_mdl_get_input_class_id_by_index(modelDesc_, 0, &calss_id);
    custom_printf("model input datatype is %d", calss_id);
    svp_acl_mdl_get_input_class_id_by_index(modelDesc_, 0, &calss_id);
    custom_printf("model output datatype is %d", calss_id);
}

bool Detection::LoadModelFromFileWithMem(const std::string &modelPath)
{
    // 把模型文件加载到内存中
    uint32_t fileSize = 0;
    modelMemPtr_ = Utils::ReadBinFile(modelPath, fileSize);
    modelMemSize_ = fileSize;

    // 从内存中加载模型
    int ret =
        svp_acl_mdl_load_from_mem(static_cast<uint8_t *>(modelMemPtr_), modelMemSize_, &modelId_);
    if (ret != SVP_ACL_SUCCESS)
    {
        svp_acl_rt_free(modelMemPtr_);
        custom_printf("load model from file failed, model file is %s,error code %#x",
                      modelPath.c_str(), ret);
        return false;
    }

    loadFlag_ = true;
    custom_printf("load model %s success", modelPath.c_str());
    return true;
}

bool Detection::CreateOutput()
{
    output_ = svp_acl_mdl_create_dataset();
    if (output_ == nullptr)
    {
        custom_printf("can't create dataset, create output failed");
        return false;
    }
    size_t outputSize = svp_acl_mdl_get_num_outputs(modelDesc_);
    for (size_t i = 0; i < outputSize; ++i)
    {
        size_t stride = svp_acl_mdl_get_output_default_stride(modelDesc_, i);
        if (stride == 0)
        {
            custom_printf("Error, output default stride is %lu.", stride);
            return false;
        }
        size_t bufferSize = svp_acl_mdl_get_output_size_by_index(modelDesc_, i);
        if (bufferSize == 0)
        {
            custom_printf("Error, output size is %lu.", bufferSize);
            return false;
        }

        // 根据模型输出的大小，申请内存
        void *outputBuffer = nullptr;
        if (svp_acl_rt_malloc(&outputBuffer, bufferSize, SVP_ACL_MEM_MALLOC_NORMAL_ONLY) !=
            SVP_ACL_SUCCESS)
        {
            custom_printf("can't malloc buffer, size is %zu, create output failed", bufferSize);
            return false;
        }
        // Utils::InitData(static_cast<int8_t*>(outputBuffer), bufferSize);

        svp_acl_data_buffer *outputData =
            svp_acl_create_data_buffer(outputBuffer, bufferSize, stride);
        if (outputData == nullptr)
        {
            custom_printf("can't create data buffer, create output failed");
            svp_acl_rt_free(outputBuffer);
            return false;
        }
        if (svp_acl_mdl_add_dataset_buffer(output_, outputData) != SVP_ACL_SUCCESS)
        {
            custom_printf("can't add data buffer, create output failed");
            svp_acl_rt_free(outputBuffer);
            svp_acl_destroy_data_buffer(outputData);
            return false;
        }
    }
    return true;
}

bool Detection::CreateInput()
{
    // 根据模型描述，获取输入的大小和格式
    size_t devSize = 0;
    size_t stride = 0;

    // only support single input model
    if (!GetInputStrideParam(0, devSize, stride, inputDims_))
    {
        custom_printf("GetInputStrideParam error");
        return false;
    }

    svp_acl_data_type dataType = svp_acl_mdl_get_input_data_type(modelDesc_, 0);
    size_t dataSize = svp_acl_data_type_size(dataType) / BYTE_BIT_NUM;
    if (dataSize == 0)
    {
        custom_printf("GetInputDataSize == 0 error");
        return false;
    }

    int bufferSize = inputDims_.dims[3] * inputDims_.dims[2] * inputDims_.dims[1];
    // custom_printf("%d , %d, %d, %d", bufferSize, inputDims_.dims[1],
    // inputDims_.dims[2], inputDims_.dims[3]); printf("Malloc input buffer %d %d
    // %d %d %d\n", bufferSize, inputDims_.dims[0], inputDims_.dims[1],
    // inputDims_.dims[2], inputDims_.dims[3]);

    // 申请输入内存， 并且初始化数据
    svp_acl_error ret =
        svp_acl_rt_malloc(&imgBufferData_, bufferSize, SVP_ACL_MEM_MALLOC_NORMAL_ONLY);

    // custom_printf("input bufferSize=%d",bufferSize);
    // custom_printf("inputDims_.dims[3]=%d,
    // inputDims_.dims[2]=%d,inputDims_.dims[1]=%d",inputDims_.dims[3],
    // inputDims_.dims[2],inputDims_.dims[1]);

    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("can't malloc buffer, size is %zu, create input failed", bufferSize);
        return false;
    }

    // Utils::InitData(static_cast<int8_t*>(imgBufferData_), bufferSize);

    // 创建输入数据集
    input_ = svp_acl_mdl_create_dataset();
    if (input_ == nullptr)
    {
        custom_printf("can't create dataset, create input failed");
        svp_acl_rt_free(imgBufferData_);
        return false;
    }

    // 创建输入数据集的内存数据块
    svp_acl_data_buffer *inputData = svp_acl_create_data_buffer(imgBufferData_, bufferSize, stride);
    if (inputData == nullptr)
    {
        custom_printf("can't create data buffer, create input failed");
        svp_acl_rt_free(imgBufferData_);
        return false;
    }

    // 添加数据块到输入数据集中
    ret = svp_acl_mdl_add_dataset_buffer(input_, inputData);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("can't add data buffer, create input failed");
        svp_acl_rt_free(imgBufferData_);
        svp_acl_destroy_data_buffer(inputData);
        return false;
    }
    return true;
}

bool Detection::SetDetParas()
{
    enum DetParaEnum
    {
        NMS_THR = 0,
        SCORE_THR = 1,
        MIN_HEIGHT = 2,
        MIN_WIDTH = 3,
    };

    std::vector<float> detPara = {0.1, 0.2, 1.0, 1.0};  // nms, score, minheight, minwidth
    void *bufPtr = nullptr;
    size_t bufferSize = sizeof(float) * detPara.size();
    svp_acl_error ret = svp_acl_rt_malloc(&bufPtr, bufferSize, SVP_ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("malloc device buffer failed");
        return false;
    }
    Utils::InitData(static_cast<int8_t *>(bufPtr), bufferSize);

    auto bufFloat = reinterpret_cast<float *>(bufPtr);
    bufFloat[NMS_THR] = detPara[NMS_THR];
    bufFloat[SCORE_THR] = detPara[SCORE_THR];
    bufFloat[MIN_HEIGHT] = detPara[MIN_HEIGHT];
    bufFloat[MIN_WIDTH] = detPara[MIN_WIDTH];
    // det para is 4 * sizeof(float) = 16 = default stride
    svp_acl_data_buffer *inputData = svp_acl_create_data_buffer(bufPtr, bufferSize, bufferSize);
    if (inputData == nullptr)
    {
        (void)svp_acl_rt_free(bufPtr);
        custom_printf("can't create data buffer, create input failed");
        return false;
    }
    ret = svp_acl_mdl_add_dataset_buffer(input_, inputData);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("add input dataset buffer failed");
        (void)svp_acl_rt_free(bufPtr);
        (void)svp_acl_destroy_data_buffer(inputData);
        inputData = nullptr;
        return false;
    }
    return true;
}

bool Detection::CreateInput(void *inputDataBuffer, size_t bufferSize, int stride)
{
    svp_acl_data_buffer *inputData =
        svp_acl_create_data_buffer(inputDataBuffer, bufferSize, stride);
    if (inputData == nullptr)
    {
        custom_printf("can't malloc buffer, size is %zu, create output failed", bufferSize);
        custom_printf("can't create data buffer, create input failed");
        return false;
    }
    // custom_printf("Input malloc buffer size is %zu", bufferSize);

    svp_acl_error ret = svp_acl_mdl_add_dataset_buffer(input_, inputData);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("add input dataset buffer failed");
        svp_acl_destroy_data_buffer(inputData);
        inputData = nullptr;
        return false;
    }

    return true;
}

bool Detection::CreateBuf(int index)
{
    void *bufPtr = nullptr;
    size_t bufSize = 0;
    size_t bufStride = 0;
    svp_acl_mdl_io_dims inDims;

    if (!GetInputStrideParam(index, bufSize, bufStride, inDims))
    {
        custom_printf("Error, GetInputStrideParam failed");
        return false;
    }

    if (svp_acl_rt_malloc(&bufPtr, bufSize, SVP_ACL_MEM_MALLOC_NORMAL_ONLY) != SVP_ACL_SUCCESS)
    {
        custom_printf("malloc device buffer failed. size is %zu", bufSize);
        return false;
    }
    Utils::InitData(static_cast<int8_t *>(bufPtr), bufSize);

    if (!CreateInput(bufPtr, bufSize, bufStride))
    {
        custom_printf("execute CreateInput failed");
        svp_acl_rt_free(bufPtr);
        return false;
    }

    return true;
}

bool Detection::CreateTaskBufAndWorkBuf()
{
    // 2 is stand taskbuf and workbuf
    if (svp_acl_mdl_get_num_inputs(modelDesc_) <= 2)
    {
        custom_printf("input dataset Num is error.");
        return false;
    }

    size_t datasetSize = svp_acl_mdl_get_dataset_num_buffers(input_);
    if (datasetSize == 0)
    {
        custom_printf("input dataset Num is 0.");
        return false;
    }

    // custom_printf("dataset size is %lu", datasetSize);
    // custom_printf("num inputs is %lu", svp_acl_mdl_get_num_inputs(modelDesc_));

    for (size_t loop = datasetSize; loop < svp_acl_mdl_get_num_inputs(modelDesc_); loop++)
    {
        if (!CreateBuf(loop))
        {
            custom_printf("execute Create taskBuffer and workBuffer failed");
            return false;
        }
    }
    return true;
}

bool Detection::Execute()
{
    svp_acl_error ret = svp_acl_mdl_execute(modelId_, input_, output_);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("execute model failed, modelId is %u,code %#x", modelId_, ret);
        return false;
    }
    // executeNum_++;
    return true;
}

bool Cmp_bbox_t(const bbox_t &veci, const bbox_t &vecj)
{
    if (veci.class_id < vecj.class_id)
    {
        return true;
    }
    else if (veci.class_id > vecj.class_id)
    {
        return false;
    }
    else if (veci.class_id == veci.class_id)
    {
        return veci.score > vecj.score;
    }
}

bool Cmp(const std::vector<float> &veci, const std::vector<float> &vecj)
{
    if (veci[CLASS_ID] < vecj[CLASS_ID])
    {
        return true;
    }
    else if (veci[CLASS_ID] == vecj[CLASS_ID])
    {
        return veci[SCORE] > vecj[SCORE];
    }
    return false;
}

std::vector<uchar> convertToYVU420SP(const std::string &imagePath)
{
    cv::Mat img = cv::imread(imagePath);
    if (img.empty())
    {
        std::cerr << "无法读取图片，请检查路径。" << std::endl;
        return std::vector<uchar>();
    }
    cv::resize(img, img, cv::Size(1280, 720), 0, 0, cv::INTER_AREA);
    int height = img.rows;
    int width = img.cols;

    cv::Mat yuv;
    cv::cvtColor(img, yuv, cv::COLOR_BGR2YUV_I420);

    std::vector<uchar> y(height * width);
    std::vector<uchar> u((height / 2) * (width / 2));
    std::vector<uchar> v((height / 2) * (width / 2));

    std::memcpy(y.data(), yuv.data, height * width);
    std::memcpy(u.data(), yuv.data + height * width, (height / 2) * (width / 2));
    std::memcpy(v.data(), yuv.data + height * width + (height / 2) * (width / 2),
                (height / 2) * (width / 2));

    std::vector<uchar> uv((height / 2) * width);
    for (size_t i = 0; i < uv.size(); i += 2)
    {
        uv[i] = v[i / 2];
        uv[i + 1] = u[i / 2];
    }

    std::vector<uchar> yvu420sp;
    yvu420sp.insert(yvu420sp.end(), y.begin(), y.end());
    yvu420sp.insert(yvu420sp.end(), uv.begin(), uv.end());

    return yvu420sp;
}
double g_pad_w = 0;
double g_pad_h = 0;
double g_ratio = 0.0;

std::vector<uchar> yvu420spToBGRPlanar(void *yvu420sp, int width, int height)
{
    std::vector<uchar> r;
    std::vector<uchar> g;
    std::vector<uchar> b;

    int uvWidth = width / 2;
    int uvHeight = height / 2;
    uchar *pdata = static_cast<uchar *>(yvu420sp);
    cv::Mat y(height, width, CV_8UC1, pdata);
    cv::Mat uv(uvHeight, width, CV_8UC1, pdata + height * width);

    cv::Mat u(uvHeight, uvWidth, CV_8UC1);
    cv::Mat v(uvHeight, uvWidth, CV_8UC1);

    for (int j = 0; j < uvHeight; ++j)
    {
        for (int i = 0; i < uvWidth; ++i)
        {
            u.at<uchar>(j, i) = uv.at<uchar>(j, 2 * i + 1);
            v.at<uchar>(j, i) = uv.at<uchar>(j, 2 * i);
        }
    }

    cv::Mat yuv(height, width, CV_8UC3);
    for (int j = 0; j < height; ++j)
    {
        for (int i = 0; i < width; ++i)
        {
            int uvX = i / 2;
            int uvY = j / 2;
            yuv.at<cv::Vec3b>(j, i)[0] = y.at<uchar>(j, i);
            yuv.at<cv::Vec3b>(j, i)[1] = u.at<uchar>(uvY, uvX);
            yuv.at<cv::Vec3b>(j, i)[2] = v.at<uchar>(uvY, uvX);
        }
    }

    cv::Mat rgb;
    cv::cvtColor(yuv, rgb, cv::COLOR_YUV2RGB);
    int input_width = 640;
    int input_height = 640;
    LetterBox letterbox(cv::Size(input_width, input_height));
    cv::Mat resized_image = letterbox(rgb, g_ratio, g_pad_w, g_pad_h);

    r.resize(input_height * input_width);
    g.resize(input_height * input_width);
    b.resize(input_height * input_width);

    for (int y = 0; y < input_height; ++y)
    {
        for (int x = 0; x < input_width; ++x)
        {
            int index = y * input_width + x;
            r[index] = resized_image.at<cv::Vec3b>(y, x)[0];
            g[index] = resized_image.at<cv::Vec3b>(y, x)[1];
            b[index] = resized_image.at<cv::Vec3b>(y, x)[2];
        }
    }

    // Combine R, G, B into a single vector
    std::vector<uchar> bgr_planar;
    bgr_planar.insert(bgr_planar.end(), r.begin(), r.end());
    bgr_planar.insert(bgr_planar.end(), g.begin(), g.end());
    bgr_planar.insert(bgr_planar.end(), b.begin(), b.end());

    return bgr_planar;
}

// 计算多边形的面积（顶点按顺序排列，顺时针或逆时针）
float Detection::PolygonArea(const std::vector<Vector>& vertices) {
    float area = 0.0f;
    int n = vertices.size();
    for (int i = 0; i < n; ++i) {
        int j = (i + 1) % n;
        area += vertices[i].X * vertices[j].Y - vertices[j].X * vertices[i].Y;
    }
    return std::abs(area) * 0.5f;
}
// 辅助函数：裁剪多边形（Sutherland-Hodgman算法）
std::vector<Vector> Detection::ClipPolygon(const std::vector<Vector>& subject, const std::vector<Vector>& clipEdge) {
    std::vector<Vector> output;
    if (subject.empty()) return output;

    Vector a = clipEdge[1] - clipEdge[0];
    Vector normal(-a.Y, a.X); // 裁剪边的法向量

    for (size_t i = 0; i < subject.size(); ++i) {
        Vector s = subject[i];
        Vector e = subject[(i + 1) % subject.size()];
        float sDist = Vector::Dot(normal, s - clipEdge[0]);  // 静态方法，传入两个向量参数
        float eDist = Vector::Dot(normal, e - clipEdge[0]);

        if (sDist >= 0) output.push_back(s);
        if ((sDist < 0 && eDist >= 0) || (eDist < 0 && sDist >= 0)) {
            float t = sDist / (sDist - eDist);
            Vector intersect = s + (e - s) * t;
            output.push_back(intersect);
        }
    }
    return output;
}

// 计算两个多边形的交集面积
float Detection::PolygonIntersectionArea(const Polygon& norecognize_area_poly, const Polygon& target_poly) {
    std::vector<Vector> intersection = norecognize_area_poly.Vertices;
    const auto& clipPoly = target_poly.Vertices;

    for (size_t i = 0; i < clipPoly.size(); ++i) {
        std::vector<Vector> clipEdge = {
            clipPoly[i],
            clipPoly[(i + 1) % clipPoly.size()]
        };
        intersection = ClipPolygon(intersection, clipEdge);
        if (intersection.empty()) break; // 无交集，提前终止
    }

    return PolygonArea(intersection);
}

// 计算两个多边形的交集面积比例（Inter）
float Detection::CalcPolygonInter(const Polygon& norecognize_area_poly, const Polygon& target_poly) {
    std::cout << "CalcPolygonInter..." << std::endl;
    float norecognizeArea = PolygonArea(norecognize_area_poly.Vertices); // 不侦测区域面积
    float targetArea = PolygonArea(target_poly.Vertices); // 目标面积  
    if (norecognizeArea <= 0 || targetArea <= 0) return 0.0f;

    float interArea = PolygonIntersectionArea(norecognize_area_poly, target_poly);
    
    if (targetArea <= 0) return 0.0f;
    return interArea / targetArea;
}

bool Detection::detect_uav(const hi_video_frame* frame, std::vector<bbox_t>& bboxes_out, bool is_yvu) 
{
    if (frame == nullptr || imgBufferData_ == nullptr)
    {
        custom_printf("Invalid input frame or buffer");
        return false;
    }

    hi_u32 g_size = 0;
    hi_pixel_format pixel_format = frame->pixel_format;
    if (pixel_format != HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420)
    {
        custom_printf("Only support HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420 format");
        return false;
    }
    g_size = frame->width * frame->height * 1.5f;  // 子码流一定要设置为1280x720，否则无法解析
    hi_phys_addr_t phys_addr = frame->phys_addr[0];
    hi_void *virt_addr = hi_mpi_sys_mmap(phys_addr, g_size);
    if (virt_addr == HI_NULL)
    {
        custom_printf("mmap data error");
        return false;
    }

    if (is_yvu)
    {
        // std::vector<uchar> yvu420sp = convertToYVU420SP("1.jpg");
        // memcpy_fast(imgBufferData_, yvu420sp.data(), yvu420sp.size() *
        // sizeof(uchar));
        memcpy_fast(imgBufferData_, virt_addr, g_size);  // 1280x720 yvu420sp(nv21)
    }
    else
    {  // bgr_planar
        std::vector<uchar> bgr_planar = yvu420spToBGRPlanar(virt_addr, frame->width, frame->height);
        memcpy_fast(imgBufferData_, bgr_planar.data(), bgr_planar.size() * sizeof(uchar));
    }

    int ret = hi_mpi_sys_munmap(virt_addr, g_size);
    if (ret != HI_SUCCESS)
    {
        custom_printf("hi_mpi_sys_munmap failed with %#x", ret);
        return false;
    }

    if (!Execute())
    {
        custom_printf("execute model failed");
        return false;
    }

    svp_acl_mdl_io_dims outDims;
    svp_acl_mdl_get_output_dims(modelDesc_, OUTPUT_NUM_ID, &outDims);
    svp_acl_data_buffer *dataBuffer = svp_acl_mdl_get_dataset_buffer(output_, OUTPUT_NUM_ID);
    auto outData = reinterpret_cast<float *>(svp_acl_get_data_buffer_addr(dataBuffer));

    const uint32_t outputDimSize = static_cast<uint32_t>(outDims.dims[outDims.dim_count - 1]);
    std::vector<int> validBoxNum(outputDimSize);
    for (uint32_t loop = 0; loop < outputDimSize; ++loop)
    {
        validBoxNum[loop] = static_cast<int>(*(outData + loop));
    }

    int totalValidNum = std::accumulate(validBoxNum.begin(), validBoxNum.end(), 0); 
    if (totalValidNum == 0) {
        return false;
    }

    svp_acl_data_buffer *dataBufferValue = svp_acl_mdl_get_dataset_buffer(output_, OUTPUT_BBOX_ID);
    auto outDataValue = reinterpret_cast<float *>(svp_acl_get_data_buffer_addr(dataBufferValue));
    svp_acl_mdl_get_output_dims(modelDesc_, OUTPUT_BBOX_ID, &outDims);
    if (outDims.dim_count <= 0)
    {
        custom_printf("aclrtOutputDims error");
        return false;
    }

    const size_t wStrideOffset =
        svp_acl_mdl_get_output_default_stride(modelDesc_, OUTPUT_BBOX_ID) / sizeof(float);
    // 模型输出的矩形包围框bbox是在640x640的图像上，需要缩放到原图尺寸，而相机主码流是3840x2160，因此做如下缩放。
    const float w_scale = 3840 / 640.0;
    const float h_scale = 2160 / 640.0;
    // const float w_scale = 1280.0 / 640.0; 
    // const float h_scale = 720.0 / 640.0;
    for (int inx = 0; inx < totalValidNum; inx++) {
        std::vector<float> bbox_recv(BBOX_SIZE, 0.0f);
        bbox_t bbox;
        for (size_t loop = 0; loop < BBOX_SIZE; loop++)
        {
            bbox_recv[loop] = (*(outDataValue + inx + loop * wStrideOffset));
        }

        bbox.score = bbox_recv[4];
        bbox.class_id = static_cast<int>(bbox_recv[5]);

        if (g_ratio == 0.0) {
            bbox.x = bbox_recv[0] * w_scale;
            bbox.y = bbox_recv[1] * h_scale;
            bbox.w = (bbox_recv[2] - bbox_recv[0]) * w_scale;
            bbox.h = (bbox_recv[3] - bbox_recv[1]) * h_scale;
        } else {
            float x0 = (bbox_recv[0] - g_pad_w) / g_ratio;  // bgr
            float y0 = (bbox_recv[1] - g_pad_h) / g_ratio;
            float x1 = (bbox_recv[2] - g_pad_w) / g_ratio;
            float y1 = (bbox_recv[3] - g_pad_h) / g_ratio;
            bbox.x = x0 * 3840.0/ 1280.0;
            bbox.y = y0 * 2160.0/ 720.0;
            bbox.w = (x1 - x0) * 3840.0/ 1280.0;
            bbox.h = (y1 - y0) * 2160.0/ 720.0;
            
        }
        const float w_scale_4k = 3840.0f;  // 4K分辨率宽度
        const float h_scale_4k = 2160.0f;
        // const float w_scale_4k = 1280.0f;  // 4K分辨率宽度
        // const float h_scale_4k = 720.0f;
         // 转换为4K相对坐标
        float x_rel = bbox.x / w_scale_4k;
        float y_rel = bbox.y / h_scale_4k;
        float w_rel = bbox.w / w_scale_4k;
        float h_rel = bbox.h / h_scale_4k;

        
        Polygon bboxPoly({
            Vector(x_rel, y_rel),
            Vector(x_rel + w_rel, y_rel),
            Vector(x_rel + w_rel, y_rel + h_rel),
            Vector(x_rel, y_rel + h_rel)
        });
        
        
        // 判断目标框与不识别区域的Inter交集是否大于阈值
        bool isHighInter = false;
        for (const auto& nonRecognitionArea : NoRecognitionAreaAttrs) {
            // 计算目标框与当前不识别区域的Inter
            float inter = CalcPolygonInter(nonRecognitionArea.poly, bboxPoly);
            std::cout << "Intersection of bbox and non-recognition area is: " << inter << std::endl;
            if (inter > INTERSECTION && isDetectionAreaDisabled) {
                std::cout << "Intersection is higher than threshold, filter this bbox" << std::endl;
                isHighInter = true;
                break;
            }
        }

        // 仅保留与所有不识别区域Inter均小于阈值的目标框
        if (!isHighInter) {
            bbox.cx = (bbox.x + (bbox.w / 2.0f)) / w_scale_4k;
            bbox.cy = (bbox.y + (bbox.h / 2.0f)) / h_scale_4k;
            bboxes_out.push_back(bbox);
        }
    }
    return true;
}

bool Detection::detect_uav_client(const hi_video_frame* frame, std::vector<bbox_t>& bboxes_out, bool is_yvu) 
{
    if (frame == nullptr || imgBufferData_ == nullptr) {
        custom_printf("Invalid input frame or buffer");
        return false;
    }

    hi_u32 g_size = 0;
    hi_pixel_format pixel_format = frame->pixel_format;
    if (pixel_format != HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
        custom_printf("Only support HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420 format");
        return false;
    }
    g_size = frame->width * frame->height * 1.5f; // 子码流一定要设置为1280x720，否则无法解析
    hi_phys_addr_t phys_addr = frame->phys_addr[0];
    hi_void* virt_addr = hi_mpi_sys_mmap(phys_addr, g_size);
    if (virt_addr == HI_NULL) {
        custom_printf("mmap data error");
        return false;
    }
    
    
    if (is_yvu) {
        // std::vector<uchar> yvu420sp = convertToYVU420SP("1.jpg");
        // memcpy_fast(imgBufferData_, yvu420sp.data(), yvu420sp.size() * sizeof(uchar));
        memcpy_fast(imgBufferData_, virt_addr, g_size); // 1280x720 yvu420sp(nv21)
    } else { // bgr_planar
        std::vector<uchar> bgr_planar = yvu420spToBGRPlanar(virt_addr, frame->width, frame->height);
        memcpy_fast(imgBufferData_, bgr_planar.data(), bgr_planar.size() * sizeof(uchar));
    }
    

    int ret = hi_mpi_sys_munmap(virt_addr, g_size);
    if (ret != HI_SUCCESS) {
        custom_printf("hi_mpi_sys_munmap failed with %#x", ret);
        return false;
    }

    if (!Execute()) {
        custom_printf("execute model failed");
        return false;
    }

    svp_acl_mdl_io_dims outDims;
    svp_acl_mdl_get_output_dims(modelDesc_, OUTPUT_NUM_ID, &outDims);
    svp_acl_data_buffer* dataBuffer = svp_acl_mdl_get_dataset_buffer(output_, OUTPUT_NUM_ID);
    auto outData = reinterpret_cast<float*>(svp_acl_get_data_buffer_addr(dataBuffer));

    const uint32_t outputDimSize = static_cast<uint32_t>(outDims.dims[outDims.dim_count - 1]);
    std::vector<int> validBoxNum(outputDimSize);
    for (uint32_t loop = 0; loop < outputDimSize; ++loop) {
        validBoxNum[loop] = static_cast<int>(*(outData + loop));
    }

    int totalValidNum = std::accumulate(validBoxNum.begin(), validBoxNum.end(), 0); 
    if (totalValidNum == 0) {
        return false;
    }

    svp_acl_data_buffer* dataBufferValue = svp_acl_mdl_get_dataset_buffer(output_, OUTPUT_BBOX_ID);
    auto outDataValue = reinterpret_cast<float*>(svp_acl_get_data_buffer_addr(dataBufferValue));
    svp_acl_mdl_get_output_dims(modelDesc_, OUTPUT_BBOX_ID, &outDims);
    if (outDims.dim_count <= 0) {
        custom_printf("aclrtOutputDims error");
        return false;
    }

    const size_t wStrideOffset = svp_acl_mdl_get_output_default_stride(modelDesc_, OUTPUT_BBOX_ID) / sizeof(float);
    // 模型输出的矩形包围框bbox是在640x640的图像上，需要缩放到原图尺寸，而相机主码流是3840x2160，因此做如下缩放。
    // const float w_scale = 3840 / 640.0; 
    // const float h_scale = 2160 / 640.0;
    const float w_scale = 1280.0 / 640.0; 
    const float h_scale = 720.0 / 640.0;
    for (int inx = 0; inx < totalValidNum; inx++) {
        std::vector<float> bbox_recv(BBOX_SIZE, 0.0f);
        bbox_t bbox;
        for (size_t loop = 0; loop < BBOX_SIZE; loop++) {
            bbox_recv[loop] = (*(outDataValue + inx + loop * wStrideOffset));
        }

        bbox.score = bbox_recv[4];
        bbox.class_id = static_cast<int>(bbox_recv[5]);

        if (g_ratio == 0.0) {
            bbox.x = bbox_recv[0] * w_scale;
            bbox.y = bbox_recv[1] * h_scale;
            bbox.w = (bbox_recv[2] - bbox_recv[0]) * w_scale;
            bbox.h = (bbox_recv[3] - bbox_recv[1]) * h_scale;
        } else {
            float x0 = (bbox_recv[0] - g_pad_w) / g_ratio;  // bgr
            float y0 = (bbox_recv[1] - g_pad_h) / g_ratio;
            float x1 = (bbox_recv[2] - g_pad_w) / g_ratio;
            float y1 = (bbox_recv[3] - g_pad_h) / g_ratio;
            bbox.x = x0 * 3840.0/ 1280.0;
            bbox.y = y0 * 2160.0/ 720.0;
            bbox.w = (x1 - x0) * 3840.0/ 1280.0;
            bbox.h = (y1 - y0) * 2160.0/ 720.0;
            
        }
        // const float w_scale_4k = 3840.0f;  // 4K分辨率宽度
        // const float h_scale_4k = 2160.0f;
        const float w_scale_4k = 1280.0f;  // 4K分辨率宽度
        const float h_scale_4k = 720.0f;
         // 转换为4K相对坐标
        float x_rel = bbox.x / w_scale_4k;
        float y_rel = bbox.y / h_scale_4k;
        float w_rel = bbox.w / w_scale_4k;
        float h_rel = bbox.h / h_scale_4k;

        
        Polygon bboxPoly({
            Vector(x_rel, y_rel),
            Vector(x_rel + w_rel, y_rel),
            Vector(x_rel + w_rel, y_rel + h_rel),
            Vector(x_rel, y_rel + h_rel)
        });
        
        
        // 判断目标框与不识别区域的Inter交集是否大于阈值
        bool isHighInter = false;
        for (const auto& nonRecognitionArea : NoRecognitionAreaAttrs) {
            // 计算目标框与当前不识别区域的Inter
            float inter = CalcPolygonInter(nonRecognitionArea.poly, bboxPoly);
            std::cout << "Intersection of bbox and non-recognition area is: " << inter << std::endl;
            if (inter > INTERSECTION && isDetectionAreaDisabled) {
                std::cout << "Intersection is higher than threshold, filter this bbox" << std::endl;
                isHighInter = true;
                break;
            }
        }

        // 仅保留与所有不识别区域Inter均小于阈值的目标框
        if (!isHighInter) {
            bbox.cx = (bbox.x + (bbox.w / 2.0f)) / w_scale_4k;
            bbox.cy = (bbox.y + (bbox.h / 2.0f)) / h_scale_4k;
            bboxes_out.push_back(bbox);
        }
    }
    return true;
}

void Detection::ProcessPerDectection(size_t detectIdx,
                                     std::vector<std::vector<float>> &vaildBox) const
{
    svp_acl_mdl_io_dims outDims;
    svp_acl_mdl_get_output_dims(modelDesc_, detectIdx, &outDims);
    svp_acl_data_buffer *dataBuffer = svp_acl_mdl_get_dataset_buffer(output_, detectIdx);
    DetectionInnerParam innerParam;
    innerParam.scoreThr = scoreThr_;
    innerParam.detectIdx = detectIdx;
    innerParam.outData = reinterpret_cast<float *>(svp_acl_get_data_buffer_addr(dataBuffer));

    innerParam.wStrideOffset =
        svp_acl_mdl_get_output_default_stride(modelDesc_, detectIdx) / sizeof(float);
    uint32_t outHeight = outDims.dims[outDims.dim_count - 2];
    innerParam.outWidth = outDims.dims[outDims.dim_count - 1];
    innerParam.chnStep = outHeight * innerParam.wStrideOffset;
    std::vector<uint32_t> expandedStrides{32, 16, 8}; /* 8: 16 : 32: anchor size */
    std::vector<uint32_t> hSizes{20, 40, 80};         // imgh / expandedStrides
    std::vector<uint32_t> wSizes{20, 40, 80};         // imgw / expandedStrides
    std::vector<std::vector<uint32_t>> anchorGrids{
        {116, 90, 156, 198, 373, 326},  // p5/32
        {30, 61, 62, 45, 59, 119},      // p4/16
        {10, 13, 16, 30, 33, 23}        // p3/8
    };

    /* gen grids */
    std::vector<float> gridsX(wSizes[detectIdx]);
    std::vector<float> gridsY(hSizes[detectIdx]);
    for (uint32_t i = 0; i < hSizes[detectIdx]; i++)
    {
        gridsY[i] = i - 0.5;  // 0.5: alg param
    }
    for (uint32_t i = 0; i < wSizes[detectIdx]; i++)
    {
        gridsX[i] = i - 0.5;  // 0.5: alg param
    }
    innerParam.objScoreOffset = 4 * innerParam.chnStep;  // 4: offset
    for (uint32_t i = 0; i < outHeight; i++)
    {
        innerParam.outHeightIdx = i;
        ProcessPerDectectionInner(innerParam, gridsX, gridsY, anchorGrids, vaildBox);
    }
}

bool Detection::GetInputStrideParam(int index, size_t &bufSize, size_t &stride,
                                    svp_acl_mdl_io_dims &dims)
{
    svp_acl_error ret = svp_acl_mdl_get_input_dims(modelDesc_, index, &dims);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("svp_acl_mdl_get_input_dims error!");
        return false;
    }
    stride = svp_acl_mdl_get_input_default_stride(modelDesc_, index);
    if (stride == 0)
    {
        custom_printf("svp_acl_mdl_get_input_default_stride error!");
        return false;
    }
    bufSize = svp_acl_mdl_get_input_size_by_index(modelDesc_, index);
    if (bufSize == 0)
    {
        custom_printf("svp_acl_mdl_get_input_size_by_index error!");
        return false;
    }
    return true;
}

void Detection::UnloadModel()
{
    // TODO
}

void Detection::DestroyResource()
{
    if (stream_ != nullptr)
    {
        if (svp_acl_rt_destroy_stream(stream_) != SVP_ACL_SUCCESS)
        {
            printf("destroy stream failed.\n");
        }
        stream_ = nullptr;
    }
    printf("end to destroy stream\n");

    if (context_ != nullptr)
    {
        if (svp_acl_rt_destroy_context(context_) != SVP_ACL_SUCCESS)
        {
            printf("destroy context failed.\n");
        }
        context_ = nullptr;
    }
    printf("end to destroy context\n");

    if (svp_acl_rt_reset_device(deviceId_) != SVP_ACL_SUCCESS)
    {
        printf("reset device failed.\n");
    }
    printf("end to reset device is %d\n", deviceId_);

    if (svp_acl_finalize() != SVP_ACL_SUCCESS)
    {
        printf("finalize acl failed.\n");
    }
    printf("end to finalize acl.\n");
}

#include <sys/stat.h>

#include <cstring>
#include <fstream>
#include <iostream>

void Utils::InitData(int8_t *data, size_t dataSize)
{
    // for (size_t i = 0; i < dataSize; i++) {
    //     data[i] = 0;
    // }
    memset(data, 0x00, dataSize);
}

bool Utils::GetFileSize(const std::string &fileName, uint32_t &fileSize)
{
    std::ifstream binFile(fileName, std::ifstream::binary);
    if (binFile.is_open() == false)
    {
        custom_printf("open file %s failed", fileName.c_str());
        return false;
    }
    binFile.seekg(0, binFile.end);
    int binFileBufferLen = binFile.tellg();
    if (binFileBufferLen == 0)
    {
        custom_printf("binfile is empty, filename is %s", fileName.c_str());
        binFile.close();
        return false;
    }
    fileSize = static_cast<uint32_t>(binFileBufferLen);
    binFile.close();
    return true;
}

bool Utils::ReadFloatFile(const std::string &fileName, std::vector<float> &detParas)
{
    struct stat sBuf;
    int fileStatus = stat(fileName.data(), &sBuf);
    if (fileStatus == -1)
    {
        custom_printf("failed to get file %s", fileName.c_str());
        return false;
    }
    if (S_ISREG(sBuf.st_mode) == 0)
    {
        custom_printf("%s is not a file, please enter a file", fileName.c_str());
        return false;
    }
    std::ifstream txtFile;
    txtFile.open(fileName);
    if (txtFile.is_open() == false)
    {
        custom_printf("open file %s failed", fileName.c_str());
        return false;
    }
    float c;
    while (!txtFile.eof())
    {
        if (!txtFile.good())
        {
            return false;
        }
        txtFile >> c;
        detParas.push_back(c);
    }
    return true;
}

void *Utils::ReadBinFile(const std::string &fileName, uint32_t &fileSize)
{
    struct stat sBuf;
    int fileStatus = stat(fileName.data(), &sBuf);
    if (fileStatus == -1)
    {
        custom_printf("failed to get file %s", fileName.c_str());
        return nullptr;
    }
    if (S_ISREG(sBuf.st_mode) == 0)
    {
        custom_printf("%s is not a file, please enter a file", fileName.c_str());
        return nullptr;
    }
    std::ifstream binFile(fileName, std::ifstream::binary);
    if (binFile.is_open() == false)
    {
        custom_printf("open file %s failed", fileName.c_str());
        return nullptr;
    }
    binFile.seekg(0, binFile.end);
    int binFileBufferLen = binFile.tellg();
    if (binFileBufferLen == 0)
    {
        custom_printf("binfile is empty, filename is %s", fileName.c_str());
        binFile.close();
        return nullptr;
    }
    binFile.seekg(0, binFile.beg);
    void *binFileBufferData = nullptr;
    svp_acl_error ret =
        svp_acl_rt_malloc(&binFileBufferData, binFileBufferLen, SVP_ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("malloc device buffer failed. size is %u", binFileBufferLen);
        binFile.close();
        return nullptr;
    }
    InitData(static_cast<int8_t *>(binFileBufferData), binFileBufferLen);

    binFile.read(static_cast<char *>(binFileBufferData), binFileBufferLen);
    binFile.close();
    fileSize = static_cast<uint32_t>(binFileBufferLen);
    return binFileBufferData;
}

void *Utils::ReadBinFileWithStride(const std::string &fileName, const svp_acl_mdl_io_dims &dims,
                                   size_t stride, size_t dataSize)
{
    struct stat sBuf;
    int fileStatus = stat(fileName.data(), &sBuf);
    if (fileStatus == -1)
    {
        custom_printf("failed to get file %s", fileName.c_str());
        return nullptr;
    }

    if (S_ISREG(sBuf.st_mode) == 0)
    {
        custom_printf("%s is not a file, please enter a file", fileName.c_str());
        return nullptr;
    }

    std::ifstream binFile(fileName, std::ifstream::binary);
    if (binFile.is_open() == false)
    {
        custom_printf("open file %s failed", fileName.c_str());
        return nullptr;
    }
    binFile.seekg(0, binFile.end);
    int binFileBufferLen = binFile.tellg();
    if (binFileBufferLen == 0)
    {
        custom_printf("binfile is empty, filename is %s", fileName.c_str());
        binFile.close();
        return nullptr;
    }
    binFile.seekg(0, binFile.beg);
    void *binFileBufferData = nullptr;
    int64_t loopTimes = 1;
    for (size_t loop = 0; loop < dims.dim_count - 1; loop++)
    {
        loopTimes *= dims.dims[loop];
    }
    size_t bufferSize = loopTimes * stride;
    svp_acl_error ret =
        svp_acl_rt_malloc(&binFileBufferData, bufferSize, SVP_ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != SVP_ACL_SUCCESS)
    {
        custom_printf("malloc device buffer failed. size is %u", binFileBufferLen);
        binFile.close();
        return nullptr;
    }
    InitData(static_cast<int8_t *>(binFileBufferData), bufferSize);

    int64_t dimValue = dims.dims[dims.dim_count - 1];
    size_t lineSize = dimValue * dataSize;
    for (int64_t loop = 0; loop < loopTimes; loop++)
    {
        binFile.read((static_cast<char *>(binFileBufferData) + loop * stride), lineSize);
    }

    binFile.close();
    return binFileBufferData;
}

void *Utils::GetDeviceBufferOfFile(const std::string &fileName, const svp_acl_mdl_io_dims &dims,
                                   size_t stride, size_t dataSize)
{
    return Utils::ReadBinFileWithStride(fileName, dims, stride, dataSize);
}
